﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace My3DGame
{
    public class clsStartState : clsStateGame
    {
        #region Field
        //cac vi tri cua camera
        float cameraX = (float)Math.Cos(1 * 0.33f);
        float cameraY = (float)Math.Sin(1 * 0.33f);
        Vector3 camPos = new Vector3(-50, 0, 20);
        // Model stuff
        ModelManager modelManager;
        public clsCamera camera { get; protected set; }
        Random rnd = new Random();
        private Game1 game1;

        // Shot variables
        float shotSpeed = 10;
        int shotDelay = 300;
        int shotCountdown = 0;

        // Crosshair
        Texture2D crosshairTexture;

        // Audio
        AudioEngine audioEngine;
        WaveBank waveBank;
        SoundBank soundBank;
        Cue trackCue;

        // Game state items
        public enum GameState { START, PLAY, LEVEL_CHANGE, END }
        GameState currentGameState = GameState.START;

        int score = 0;
        SpriteFont scoreFont;

        // Powerup stuff
        int originalShotDelay = 300;
        public enum PowerUps { NONE, RAPID_FIRE, MULTI_SHOT }
        int shotDelayRapidFire = 100;
        int rapidFireTime = 10000;
        int powerUpCountdown = 0;
        string powerUpText = "";
        int powerUpTextTimer = 0;
        SpriteFont powerUpFont;
        PowerUps currentPowerUp = PowerUps.NONE;
        //tao moi doi tuong kieu Terrian
        clsTerrain terrian;
        //tao moi doi tuong kieu Sky
        clsSky sky;
        static SpriteBatch _sb;

        public static SpriteBatch sb
        {
            get { return _sb; }
            set { _sb = value; }
        }

        static Texture2D _txtSky;

        public static Texture2D txtSky
        {
            get { return _txtSky; }
            set { _txtSky = value; }
        }

        //khai bao doi tuong Spaceship
        Spaceship spaceship;

        #endregion

        #region Initilization
        public clsStartState(Game1 game1)
        {
            spaceship = new Spaceship(game1);
            // Set preferred resolution
            //graphics.PreferredBackBufferWidth = 1280;
            //graphics.PreferredBackBufferHeight = 1024;
            this.game1 = game1;

            // If not running debug, run in full screen
#if !DEBUG
    graphics.IsFullScreen = true;
#endif
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        public override void Initialize(Game1 game1)
        {
            // Initialize Camera
            camera = new clsCamera(this, new Vector3(0, 0, 50),Vector3.Zero, Vector3.Up);
            Components.Add(camera);

            // Initialize model manager
            modelManager = new ModelManager(this, game1, camera);
            Components.Add(modelManager);
            modelManager.Enabled = true;
            modelManager.Visible = true;

            //khoi tao doi tuong Terrian
            terrian = new clsTerrain(game1);
            terrian.loadContent(game1.Content);
            //khoi tao doi tuong Sky
            sky = new clsSky();
            base.Initialize();
        }

        #endregion

        #region LoadContent and UnLoadContent
        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        public override void LoadContent(Game1 game1)
        {

            // Load the crosshair texture
            crosshairTexture = game1.Content.Load<Texture2D>(@"textures\crosshair");

            // Load sounds and play initial sounds
            audioEngine = new AudioEngine(@"Content\Audio\GameAudio.xgs");
            waveBank = new WaveBank(audioEngine, @"Content\Audio\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, @"Content\Audio\Sound Bank.xsb");

            // Play the soundtrack
            trackCue = soundBank.GetCue("Tracks");
            trackCue.Play();

            // Load fonts
            scoreFont = game1.Content.Load<SpriteFont>(@"Fonts\ScoreFont");
            powerUpFont = game1.Content.Load<SpriteFont>(@"fonts\PowerupFont");

            //Load content for Spaceship
            spaceship.loadContent(Content);
            
            
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        #endregion

        #region Update
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime, Game1 game1)
        {
            modelManager.Update(gameTime);

            //xu ly su kien cho ban phim, chuot, ...
            HandleInput(gameTime);
            // Update power-up timer
            UpdatePowerUp(gameTime);
            
            base.Update(gameTime);
        }
        #endregion

        #region Draw
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime, Game1 game1)
        {
            game1.GraphicsDevice.Clear(Color.Black);
            base.Draw(gameTime);
            // Only draw crosshair if in play game state
            //if (currentGameState == GameState.PLAY)
            {
                game1.spriteBatch.Begin();
                //spriteBatch.Draw(txtSky,Vector2.Zero,Color.White);
                #region Draw the crosshair
                game1.spriteBatch.Draw(crosshairTexture,
                    new Vector2((Window.ClientBounds.Width / 2)
                        - (crosshairTexture.Width / 2),
                        (Window.ClientBounds.Height / 2)
                        - (crosshairTexture.Height / 2)),
                        Color.White);
                #endregion

                #region Draw the current score
                string scoreText = "Score: " + score;
                game1.spriteBatch.DrawString(scoreFont, scoreText, new Vector2(10, 10), Color.Red);
                #endregion

                #region Let the player know how many misses he has left
                game1.spriteBatch.DrawString(scoreFont, "Misses Left: " + modelManager.missesLeft,
                    new Vector2(10, scoreFont.MeasureString(scoreText).Y + 20), Color.Red);
                #endregion

                #region If power-up text timer is live, draw power-up text
                if (powerUpTextTimer > 0)
                {
                    powerUpTextTimer -= gameTime.ElapsedGameTime.Milliseconds;
                    Vector2 textSize = powerUpFont.MeasureString(powerUpText);
                    game1.spriteBatch.DrawString(powerUpFont,
                        powerUpText,
                        new Vector2((Window.ClientBounds.Width / 2) - (textSize.X / 2),
                        (Window.ClientBounds.Height / 2) - (textSize.Y / 2)),
                        Color.Goldenrod);
                }
                #endregion

                Vector3 cameraPosition = camPos;
                Vector3 cameraFront = new Vector3(-cameraY, 0, cameraX);

                Vector3 cameraTarget = cameraPosition + cameraFront;

                Matrix view = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
                Matrix world;
                world = Matrix.CreateRotationY(-MathHelper.PiOver4 / 2f);
                world *= Matrix.CreateTranslation(camPos + (cameraTarget - camPos) * 64f) * Matrix.CreateTranslation(cameraPosition - new Vector3(-50, 15, 20));

                Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                                                            game1.GraphicsDevice.Viewport.AspectRatio,
                                                            1, 10000);
                spaceship.Draw(view, world, projection);
                modelManager.Draw(gameTime);

                game1.spriteBatch.End();
            }
        }
        #endregion

        protected void FireShots(GameTime gameTime)
        {
            if (shotCountdown <= 0)
            {
                // Did player press space bar or left mouse button?
                if (Keyboard.GetState().IsKeyDown(Keys.Space) ||
                    Mouse.GetState().LeftButton == ButtonState.Pressed)
                {

                    if (currentPowerUp != PowerUps.MULTI_SHOT)
                    {
                        //Normal mode - fire one shot

                        // Add a shot to the model manager
                        modelManager.AddShot(
                            camera.cameraPosition + new Vector3(0, -5, 0),
                            camera.GetCameraDirection * shotSpeed);
                    }
                    else
                    {
                        //Multi-shot mode!

                        //Add shot in spread to the top right
                        Vector3 initialPosition = camera.cameraPosition +
                            Vector3.Cross(camera.GetCameraDirection, camera.cameraUp) * 5
                            + (camera.cameraUp * 5);
                        modelManager.AddShot(
                            initialPosition + new Vector3(0, -5, 0),
                            camera.GetCameraDirection * shotSpeed);

                        //Add shot in spread to the bottom right
                        initialPosition = camera.cameraPosition +
                            Vector3.Cross(camera.GetCameraDirection, camera.cameraUp) * 5
                            - (camera.cameraUp * 5);
                        modelManager.AddShot(
                            initialPosition + new Vector3(0, -5, 0),
                            camera.GetCameraDirection * shotSpeed);

                        //Add shot in spread top left
                        initialPosition = camera.cameraPosition -
                            Vector3.Cross(camera.GetCameraDirection, camera.cameraUp) * 5
                            + (camera.cameraUp * 5);
                        modelManager.AddShot(
                            initialPosition + new Vector3(0, -5, 0),
                            camera.GetCameraDirection * shotSpeed);

                        //Add shot in spread bottom left
                        initialPosition = camera.cameraPosition -
                            Vector3.Cross(camera.GetCameraDirection, camera.cameraUp) * 5
                            - (camera.cameraUp * 5);
                        modelManager.AddShot(
                            initialPosition + new Vector3(0, -5, 0),
                            camera.GetCameraDirection * shotSpeed);
                    }

                    // Play shot audio
                    PlayCue("Shot");

                    // Reset the shot countdown
                    shotCountdown = shotDelay;
                }
            }
            else
                shotCountdown -= gameTime.ElapsedGameTime.Milliseconds;
        }

        public void PlayCue(string cue)
        {
            soundBank.PlayCue(cue);
        }

        public void AddPoints(int points)
        {
            score += points;
        }

        private void CancelPowerUps()
        {
            modelManager.consecutiveKills = 0;
            shotDelay = originalShotDelay;
            currentPowerUp = PowerUps.NONE;

        }

        protected void UpdatePowerUp(GameTime gameTime)
        {
            if (powerUpCountdown > 0)
            {
                powerUpCountdown -= gameTime.ElapsedGameTime.Milliseconds;
                if (powerUpCountdown <= 0)
                {
                    CancelPowerUps();
                    powerUpCountdown = 0;
                }
            }
        }

        public void StartPowerUp()
        {
            if (rnd.Next(2) == 0)
                currentPowerUp = PowerUps.RAPID_FIRE;
            else
                currentPowerUp = PowerUps.MULTI_SHOT;

            switch (currentPowerUp)
            {
                case PowerUps.RAPID_FIRE:
                    shotDelay = shotDelayRapidFire;
                    powerUpCountdown = rapidFireTime;
                    powerUpText = "Rapid Fire Mode!";
                    powerUpTextTimer = 1000;
                    soundBank.PlayCue("RapidFire");
                    break;
                case PowerUps.MULTI_SHOT:
                    powerUpCountdown = rapidFireTime;
                    powerUpText = "Multi-shot Mode!";
                    powerUpTextTimer = 1000;
                    soundBank.PlayCue("RapidFire");
                    break;
            }
        }

        private void HandleInput(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // Only check for shots if you're in the play game state
            //if (currentGameStae == GameState.PLAY)
            {
                // See if the player has fired a shot
                FireShots(gameTime);
            }
        }
    }
}
